﻿/*-------------------------------------------------------------------------
* 命名空间: WaferSelectV3.ViewModels/IndexViewModel
* 类       名: IndexViewModel
* 功      能:  TD
* 时      间:  2024-04-29 17:45:15
* 版      本:  V1.0
* 作      者:  Fioman
* 格      言:  Talk is cheap,show me the code ^_^
*-------------------------------------------------------------------------*/
using Microsoft.EntityFrameworkCore.SqlServer.Query.Internal;
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Regions;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
using WaferSelectV3.Common;
using WaferSelectV3.DAL.DataEntity;
using WaferSelectV3.DAL.LocalDataAccess;
using WaferSelectV3.Dialogs;
using WaferSelectV3.EventsManager;
using WaferSelectV3.Extensions;
using WaferSelectV3.Models;
using WaferSelectV3.PlcCommunication;
using WaferSelectV3.Services;

namespace WaferSelectV3.ViewModels
{
    public class IndexViewModel : BindableBase, INavigationAware
    {
        private readonly IEventAggregator _eventAggregator;
        public WorkingInfoEntity? RecipeInput;
        public bool WorkingCrystalIsFinish = false; // 作业工单是否接单完成
        /// <summary>
        /// 导航到这个界面的时候调用的方法
        /// </summary>
        /// <param name="navigationContext"></param>
        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            Task.Run(() =>
            {
                ReloadShieldModules();
            });
        }


        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }

        /// <summary>
        /// 导航离开的时候调用的方法
        /// </summary>
        /// <param name="navigationContext"></param>
        public void OnNavigatedFrom(NavigationContext navigationContext)
        {

        }
        public IndexViewModel(IEventAggregator eventAggregator)
        {
            _eventAggregator = eventAggregator;

            // 1. 命令绑定
            GetCrystalLevelCountsCommand = new DelegateCommand<string>(DoGetCrystalLevelCounts);
            InputNextCrystalCommand = new DelegateCommand(DoInputNextCrystal);
            ChangeNextCrystalCommand = new DelegateCommand(DoChangeNextCrystal).ObservesCanExecute(() => NextCrystalIsOk);
            ModuleShieldChangedCommand = new DelegateCommand(DoModuleShieldChanged);
            DeviceOperateCommand = new DelegateCommand<string>(DoDeviceOpearte);

            ReloadWorkingInfo();
            ReloadSlaveParams();
            // 3. 从数据库中加载当前晶棒的统计的等级和数量信息
            ReloadCystalLevelCount();
            // 2. 从数据库中加载当前作业信息
            ReloadWorkingInfo();
            // 4. 加载工单目录文件,以及选择当前作业工单
            ReloadProductionRecipeFiles();
            // 5. 加载从站通信IP地址端口号
            ReloadSlaveParams();
            // 6. 加载作业工单的检测规则
            ReloadDetectedRules();
            // 7. 加载视觉补偿表
            ReloadVisionOffsets();
            // 9. 加载料盒信息,从数据库,如果数据库存在的话,如果不存在就是从工单,工单切换的时候,或者是工单修改的时候,这里要重新加载一次.
            ReloadBoxStates();
            // 10. 加载料盒列表信息
            ReloadBoxNameList();
            // 11. 创建ResultSummary表,如果存在就创建
            WaferSummaryAccess.CreateWaferSummaryTable(WorkingInfo.CurrentCrystalNumber!);

            // 6. 启动异步任务
            StartAsyncTask();

            // 7 . 事件订阅
            _eventAggregator.GetEvent<WindowSizeChangedEvent>().Subscribe(SetUiElementSize);
        }



        private async void StartAsyncTask()
        {
            // 1. Plc通信模块,监控Plc连接还有一些料盒状态
            Task plcMonitorTask = PlcMonitorTask();
            // 2. 尺寸工位
            Task socketTaskSize = SizeServerTask();
            // 3. 崩边隐裂工位
            Task socketTaskEdgeSub = EdgeSubServerTask();
            // 4. 3D工位
            Task socketTask3D = ThreeDServerTask();
            // 5. 脏污工位
            Task socketTaskSmudge = SmudgeServerTask();
            await Task.WhenAll(plcMonitorTask, socketTaskSize, socketTaskEdgeSub, socketTask3D,
                socketTaskSmudge);
        }


        /// <summary>
        /// PLC客户端对象,PLC的所有的操作都调用这个
        /// </summary>
        private BeckhoffPlcClient PlcClient = BeckhoffPlcClient.Instance;
        private CancellationTokenSource _tokenPlcMonitor = new CancellationTokenSource();
        private async Task PlcMonitorTask()
        {
            string taskName = "1. 电阻率流水号读取的异步任务_PlcMonitorTask";
            try
            {
                LoggerHelper.WriteLogMain($"{taskName} 开始.");
                while (!_tokenPlcMonitor.IsCancellationRequested)
                {
                    if (SlaveStatePlc.DisConnectedCount >= 5)
                    {
                        await Task.Delay(2000);
                        continue;
                    }
                    // 1. 读取PLC状态,如果不在线,就去连接PLC
                    if (!SlaveStatePlc.IsOnline)
                    {
                        await Task.Run(() =>
                        {
                            DataResult result = PlcClient.ConnectPlc(SlaveStatePlc.SlaveIp!, SlaveStatePlc.SlavePort);
                            Application.Current?.Dispatcher.Invoke(() =>
                            {
                                SlaveStatePlc.IsOnline = result.State;
                                SlaveStatePlc.DisConnectedCount = result.State ? 0 : SlaveStatePlc.DisConnectedCount + 1;
                            });
                        });
                        if (!SlaveStatePlc.IsOnline)
                        {
                            await Task.Delay(1000);
                            continue;
                        }
                    }

                    // 2. 获取电阻率触发信号,一直读取电阻率的信息
                    DataResult<int> idResult = PlcClient.GetWaferIdForResistivity();
                    if (idResult.State)
                    {
                        int waferIdFromPlc = idResult.Data!;
                        // 如果发现流水号比上一次流水号变大了,并且获取到的流水号不是0,就认为有新的流水号了
                        if (waferIdFromPlc > GlobalValues.LastResistivityId && waferIdFromPlc > 0)
                        {
                            GlobalValues.LastResistivityId = waferIdFromPlc;
                            GlobalValues.WaferIdQueue.Enqueue(waferIdFromPlc);
                            LoggerHelper.WriteLogMain($"收到电阻率流水号变化,读取流水号:{waferIdFromPlc}", LogType.Info);
                            // 3. 料盒写入测试,正常作业的时候要弄掉
                            TestWriteBoxNumber(waferIdFromPlc);
                        }
                    }
                    else
                    {
                        LoggerHelper.WriteLogMain(idResult.Message!, LogType.Exception);
                    }
                    await Task.Delay(5); // 休眠5ms
                }
            }
            catch (Exception ex)
            {
                LoggerHelper.WriteLogMain($"{taskName}出现异常: {ex.GetFullException()}", LogType.Exception);
            }
            finally
            {
                LoggerHelper.WriteLogMain($"{taskName}结束.");
            }
        }

        private SocketServer? SizeServer;
        private CancellationTokenSource _tokenSizeServer = new CancellationTokenSource();
        /// <summary>
        /// 尺寸工位Socket异步服务器
        /// </summary>
        /// <returns></returns>
        private async Task SizeServerTask()
        {
            string taskName = "2. 尺寸服务器异步任务_SizeServerTask";
            try
            {
                LoggerHelper.WriteLogMain($"{taskName} 开始.");
                SizeServer = new SocketServer(SlaveStateSize!);
                await SizeServer.StartServerAsync(_tokenSizeServer);
                if (_tokenSizeServer.IsCancellationRequested)
                {
                    LoggerHelper.WriteLogMain($"{taskName} 的服务异步任务通过token取消.");
                }
            }
            catch (Exception ex)
            {
                LoggerHelper.WriteLogMain($"{taskName}出现异常: {ex.GetFullException()}", LogType.Exception);
            }
            finally
            {
                LoggerHelper.WriteLogMain($"{taskName}结束.");
            }
        }


        private SocketServer? EdgeSubServer;
        private CancellationTokenSource _tokenEdgeSubServer = new CancellationTokenSource();
        /// <summary>
        /// 崩边隐裂服务器
        /// </summary>
        /// <returns></returns>
        private async Task EdgeSubServerTask()
        {
            string taskName = "3. 崩边隐裂服务器异步任务_EdgeSubServerTask";
            try
            {
                LoggerHelper.WriteLogMain($"{taskName} 开始.");
                EdgeSubServer = new SocketServer(SlaveStateEdgeSub!);
                await EdgeSubServer.StartServerAsync(_tokenEdgeSubServer);
                if (_tokenEdgeSubServer.IsCancellationRequested)
                {
                    LoggerHelper.WriteLogMain($"{taskName} 的服务异步任务通过token取消.");
                }
            }
            catch (Exception ex)
            {
                LoggerHelper.WriteLogMain($"{taskName}出现异常: {ex.GetFullException()}", LogType.Exception);
            }
            finally
            {
                LoggerHelper.WriteLogMain($"{taskName}结束.");
            }
        }

        /// <summary>
        /// 3D服务器异步任务
        /// </summary>
        private SocketServer? ThreeDServer;
        private CancellationTokenSource _tokenThreeDServer = new CancellationTokenSource();
        private async Task ThreeDServerTask()
        {
            string taskName = "4. 3D服务器异步任务_ThreeDServerTask";
            try
            {
                LoggerHelper.WriteLogMain($"{taskName} 开始.");
                ThreeDServer = new SocketServer(SlaveState3D!);
                await ThreeDServer.StartServerAsync(_tokenThreeDServer);
                if (_tokenThreeDServer.IsCancellationRequested)
                {
                    LoggerHelper.WriteLogMain($"{taskName} 的服务异步任务通过token取消.");
                }
            }
            catch (Exception ex)
            {
                LoggerHelper.WriteLogMain($"{taskName}出现异常: {ex.GetFullException()}", LogType.Exception);
            }
            finally
            {
                LoggerHelper.WriteLogMain($"{taskName}结束.");
            }
        }

        /// <summary>
        ///  脏污服务器的异步任务
        /// </summary>
        private SocketServer? SmudgeServer;
        private CancellationTokenSource _tokenSmudgeServer = new CancellationTokenSource();
        private async Task SmudgeServerTask()
        {
            string taskName = "4. 脏污服务器异步任务_SmudgeServerTask";
            try
            {
                LoggerHelper.WriteLogMain($"{taskName} 开始.");
                SmudgeServer = new SocketServer(SlaveStateSmudge!);
                await SmudgeServer.StartServerAsync(_tokenSmudgeServer);
                if (_tokenSmudgeServer.IsCancellationRequested)
                {
                    LoggerHelper.WriteLogMain($"{taskName} 的服务异步任务通过token取消.");
                }
            }
            catch (Exception ex)
            {
                LoggerHelper.WriteLogMain($"{taskName}出现异常: {ex.GetFullException()}", LogType.Exception);
            }
            finally
            {
                LoggerHelper.WriteLogMain($"{taskName}结束.");
            }
        }


        private void TestWriteBoxNumber(int waferId)
        {
            int boxNumber;
            if (GlobalValues.IsFixedBox)
            {
                boxNumber = GlobalValues.boxInto;
            }
            else
            {
                boxNumber = RandomHelper.GetRandomInt(1, 19);
            }
            DataResult result = PlcClient.WriteBoxNumber(waferId, boxNumber);
            if (result.State)
            {
                LoggerHelper.WriteLogMain($"测试分选料盒写入,流水号:{waferId},料盒:{boxNumber}");
            }
            else
            {
                AppCloseProvider.CloseAppWithErrorHappen(result.Message!);
            }
        }



        #region 1. 一些按钮的命令
        /// <summary>
        /// 晶棒统计按钮分为当前和前一晶棒,带有参数Current,Last
        /// </summary>
        public DelegateCommand<string> GetCrystalLevelCountsCommand { get; private set; }
        private void DoGetCrystalLevelCounts(string crystalNumber)
        {
            string searchCrystalNumber;
            if (crystalNumber.ToLower() == "current")
            {
                searchCrystalNumber = WorkingInfo.CurrentCrystalNumber!;
            }
            else
            {
                searchCrystalNumber = WorkingInfo.LastCrystalNumber!;
                CurrentCrystalIsChecked = false;
            }

            var result = CrystalLevelCountAccess.GetLevelCountsByCrystalNumber(searchCrystalNumber);
            if (result.State)
            {
                var levelCountRes = result.Data;
                LevelCountsList.Clear();
                if (levelCountRes!.Count > 0)
                {
                    foreach (var lvCountEntity in levelCountRes)
                    {
                        var temp = new CrystalLevelCountModel()
                        {
                            LevelIndex = lvCountEntity.LevelIndex,
                            DetectedType = lvCountEntity.LevelType,
                            DetectedCount = lvCountEntity.Count,
                        };
                        LevelCountsList.Add(temp);
                    }
                }
            }
            else
            {
                LoggerHelper.WriteLogMain(result.Message!, LogType.Fatal);
            }
        }

        /// <summary>
        /// 工单切换,输入下一单,切换下一单
        /// </summary>
        public DelegateCommand InputNextCrystalCommand { get; private set; }
        public DelegateCommand ChangeNextCrystalCommand { get; private set; }

        private void DoInputNextCrystal()
        {
            IDialogParameters parameters = new DialogParameters()
            {
                {"Title","下一单信息录入窗口" },
                {"WorkingInfo",WorkingInfo }
            };
            var result = DialogProvider.ShowDialog(nameof(InputNextCrystalDialog), parameters);
            if (result.Result == ButtonResult.OK)
            {
                // 下一单录入成功,将下一单的信息带入回来.
                RecipeInput = result.Parameters.GetValue<WorkingInfoEntity>(nameof(WorkingInfoEntity));
                NextCrystalIsOk = true;
            }
            else
            {
                NextCrystalIsOk = false;
                // 下一单录入失败,没有确认,就什么也不做就行了
            }
        }
        /// <summary>
        /// 切换下一单任务
        /// </summary>
        private void DoChangeNextCrystal()
        {
            MessageBoxResult res = MessageBox.Show("确定要切换到下一单吗 (●__●)", "操作提示", MessageBoxButton.OKCancel, MessageBoxImage.Warning);
            if (res == MessageBoxResult.OK)
            {
                // 1. 清空视觉数据队列信号
                DataResult initResult = DataReset();
                if (!initResult.State)
                {
                    string errorInfo = $"数据复位初始化失败: {initResult.Message}";
                    LoggerHelper.WriteLogMain(errorInfo, LogType.Fatal);
                    MessageBox.Show(errorInfo, "工单切换失败提示框", MessageBoxButton.OK, MessageBoxImage.Error);
                }
                // 2. 3D标定要做的事情
                // 3. 做工单切换的任务
                DoChangeCrystalWork();
                NextCrystalIsOk = false; // 输入下一单置位False,切换下一单设置为不可用
                WorkingCrystalIsFinish = false; // 结单状态置位未结单
                // 4. 数据初始化,最要是一些队列数据进行清空
                // TODO: 5. 如果上料状态是关闭的要打开上料
            }
        }

        /// <summary>
        /// 使用到的队列和字典数据复位
        /// </summary>
        /// <returns></returns>
        private DataResult DataReset()
        {
            DataResult result = new DataResult();
            try
            {
                result.State = true;
            }
            catch (Exception ex)
            {
                result.Message = ex.GetFullException();
            }
            return result;
        }

        private void DoChangeCrystalWork()
        {
            Task.Run(() =>
            {
                // 1.如果要切换的晶棒编号和当前作业的晶棒编号不相同
                if (RecipeInput!.CurrentCrystalNumber != WorkingInfo.CurrentCrystalNumber)
                {
                    string lastCrystalDelete = WorkingInfo.LastCrystalNumber!;
                    string currentCrystal = WorkingInfo.CurrentCrystalNumber!;
                    string nextCrystal = RecipeInput.CurrentCrystalNumber!;
                    // 2. 创建新的晶棒编号的汇总表
                    DataResult result = WaferSummaryAccess.CreateWaferSummaryTable(nextCrystal);
                    if (!result.State)
                    {
                        AppCloseProvider.CloseAppWithErrorHappen(result.Message!);
                    }

                    // 3. 将当前的晶棒的统计信息保存到历史记录中去
                    var curentResult = CrystalLevelCountAccess.GetLevelCountsByCrystalNumber(currentCrystal);
                    if (!curentResult.State)
                    {
                        AppCloseProvider.CloseAppWithErrorHappen(curentResult.Message!);
                    }
                    var levelCount = curentResult.Data!;
                    int normalLevelCount = levelCount.Count - GlobalValues.DetectedTypeNamesDefineSelf.Count();
                    LevelCountHistoryEntity currentRecord = new LevelCountHistoryEntity()
                    {
                        Lv01 = normalLevelCount >= 1 ? levelCount[0].Count : 0,
                        Lv02 = normalLevelCount >= 2 ? levelCount[1].Count : 0,
                        Lv03 = normalLevelCount >= 3 ? levelCount[2].Count : 0,
                        Lv04 = normalLevelCount >= 4 ? levelCount[3].Count : 0,
                        Lv05 = normalLevelCount >= 5 ? levelCount[4].Count : 0,
                        Lv06 = normalLevelCount >= 6 ? levelCount[5].Count : 0,
                        Lv07 = normalLevelCount >= 7 ? levelCount[6].Count : 0,
                        Lv08 = normalLevelCount >= 8 ? levelCount[7].Count : 0,
                        Lv09 = normalLevelCount >= 9 ? levelCount[8].Count : 0,
                        Lv10 = normalLevelCount >= 10 ? levelCount[9].Count : 0,
                        Lv11 = normalLevelCount >= 11 ? levelCount[10].Count : 0,
                        Lv12 = normalLevelCount >= 12 ? levelCount[11].Count : 0,
                        Lv13 = normalLevelCount >= 13 ? levelCount[12].Count : 0,
                        Lv14 = normalLevelCount >= 14 ? levelCount[13].Count : 0,
                        Lv15 = normalLevelCount >= 15 ? levelCount[14].Count : 0,
                        Lv16 = normalLevelCount >= 16 ? levelCount[15].Count : 0,
                        Lv17 = normalLevelCount >= 17 ? levelCount[16].Count : 0,
                        Lv18 = normalLevelCount >= 18 ? levelCount[17].Count : 0,
                        // 倒数第一个数
                        Lv39 = levelCount[^1].Count,
                        Lv38 = levelCount[^2].Count,
                        Lv37 = levelCount[^3].Count,
                        Lv36 = levelCount[^4].Count,
                        Lv35 = levelCount[^5].Count,
                        Lv34 = levelCount[^6].Count,
                        Lv33 = levelCount[^7].Count,
                        Lv32 = levelCount[^8].Count,
                        Lv31 = levelCount[^9].Count,

                    };
                    result = LevelCountHistoryAccess.AddLevelCountHistorySingle(currentRecord);
                    if (!result.State)
                    {
                        AppCloseProvider.CloseAppWithErrorHappen(result.Message!);
                    }

                    // 4. 如果发现当前晶棒编号和前一个晶棒编号是相同的话,也不要删除了,如果删除的话就删除了两条数据了
                    if (!lastCrystalDelete.Equals(currentCrystal) && !lastCrystalDelete.Equals(nextCrystal))
                    {
                        // 将上一个晶棒编号的信息移除掉
                        CrystalLevelCountAccess.DeleteDataByCrystalNumber(lastCrystalDelete);
                    }

                    // 5. 先将作业工单信息保存到WorkingInfo中去,然后重新加载WorkingInfo和CystalLevelCount
                    WorkingInfo.CurrentCrystalNumber = nextCrystal;
                    WorkingInfo.LastCrystalNumber = currentCrystal;
                    result = WorkingInfoAccess.UpdateWorkingInfo(WorkingInfo);
                    if (!result.State)
                    {
                        AppCloseProvider.CloseAppWithErrorHappen(result.Message!);
                    }
                    Application.Current?.Dispatcher?.Invoke(() =>
                    {
                        ReloadWorkingInfo();
                        ReloadCystalLevelCount();
                    });
                    // 6. 创建目录,保存当前工单汇总表的目录
                    PathDirProvider.CreateSummaryDir(WorkingInfo.CurrentCrystalNumber);
                }
            });
        }

        /// <summary>
        /// 屏蔽状态发生改变的按钮
        /// 1. 将数据保存到数据库,然后重新加载数据
        /// </summary>
        public DelegateCommand ModuleShieldChangedCommand { get; private set; }
        private void DoModuleShieldChanged()
        {
            List<ModuleShieldEntity> updateData = new List<ModuleShieldEntity>();
            foreach (var model in TotalModuleShieldStates)
            {
                updateData.Add(new ModuleShieldEntity { Id = model.Id, ModuleName = model.ModuleName, IsShielded = model.IsShielded });
            }

            DataResult dataresult = ModuleShieldAccess.UpdateDataMany(updateData);
            if (dataresult.State)
            {
                ReloadShieldModules();
            }
            else
            {
                LoggerHelper.WriteLogMain(dataresult.Message!, LogType.Fatal);
            }
        }

        /// <summary>
        /// 设备操作的命令,根据命令参数来选择对应的操作
        /// </summary>
        public DelegateCommand<string> DeviceOperateCommand { get; private set; }
        private void DoDeviceOpearte(string parameter)
        {
            if (parameter != null)
            {
                switch (parameter)
                {
                    case "InitData":
                        var res = MessageBox.Show("上电初始化用来软件掉线开启时使用,作业过程中禁止使用!", "上电初始化操作提示", MessageBoxButton.OKCancel, MessageBoxImage.Warning);
                        if (res == MessageBoxResult.OK)
                        {
                            PowerOnDataInit();
                        }
                        break;
                }
            }
        }

        /// <summary>
        /// 上电初始化, 做一些清理工作.
        /// </summary>
        private async void PowerOnDataInit()
        {
            lock (new object())
            {
                GlobalValues.WaferIdLevelDictionary.Clear();
                GlobalValues.WaferIdHeaderClientMap.Clear();
                GlobalValues.WaferIdDateSummary.Clear();
                GlobalValues.WaferIdQueue.Clear();
                GlobalValues.WaferIdResistivityValMap.Clear();
                GlobalValues.WaferIdDataComman.Clear();
                GlobalValues.WaferIdData3d01.Clear();
                GlobalValues.WaferIdData3D02.Clear();
                GlobalValues.WaferIdDataResistivity.Clear();
                GlobalValues.WaferIdDataSize.Clear();
                GlobalValues.WaferIdDataEdgeBreak.Clear();
                GlobalValues.WaferIdDataSmudge.Clear();
                GlobalValues.WaferIdDataSubfissure.Clear();
                GlobalValues.VisionErrorWithWaferId.Clear();
            }
            // 如果
            if (SlaveStatePlc.IsOnline)
            {
                PlcClient.ResetResistivityWaferId(); // 重置电阻率流水号
                lock (new object())
                {
                    GlobalValues.LastResistivityId = 0; // 将上一个电阻率的流水号清空
                }
            }
            // 对所有的分站发送队列清空消息
            SendClearMsgToAllSlave();
            IDialogParameters dialogParams = new DialogParameters()
            {
                { "serverArray",new SocketServer[]{SizeServer!,ThreeDServer!,SmudgeServer!,EdgeSubServer!} }
            };
            // 弹出进度条,并发送消息
            DialogProvider.Show(nameof(DataInitProcessBar), dialogParams);
            await Task.Delay(1500);
            string errorInfo = string.Empty; // 上电初始化是否有异常发生
            if (!ModuleShieldedList.Contains("尺寸") && !SizeServer!.ClearResponseIsOk)
            {
                errorInfo += "尺寸工位数据初始化失败,没有收到回复.";
            }
            if (!ModuleShieldedList.Contains("3D") && !ThreeDServer!.ClearResponseIsOk)
            {
                errorInfo += "3D工位数据初始化失败,没有收到回复.";
            }
            if (!ModuleShieldedList.Contains("隐裂") && !EdgeSubServer!.ClearResponseIsOk)
            {
                errorInfo += "崩边隐裂工位数据初始化失败,没有收到回复.";
            }
            if (!ModuleShieldedList.Contains("上脏污") && !SmudgeServer!.ClearResponseIsOk)
            {
                errorInfo += "上下脏污工位数据初始化失败,没有收到回复.";
            }
            if (!string.IsNullOrEmpty(errorInfo))
            {
                MessageBox.Show($"错误: {errorInfo}", "上电初始化失败", MessageBoxButton.OK, MessageBoxImage.Error);
                LoggerHelper.WriteLogMain($"上电初始化失败: {errorInfo}", LogType.Fatal);
            }
            else
            {
                LoggerHelper.WriteLogMain("上电初始化执行成功");
            }
        }


        /// <summary>
        /// 发送数据初始化消息,视觉工作初始化
        /// </summary>
        private void SendClearMsgToAllSlave()
        {
            SizeServer!.ClearResponseIsOk = false;
            SmudgeServer!.ClearResponseIsOk = false;
            ThreeDServer!.ClearResponseIsOk = false;
            EdgeSubServer!.ClearResponseIsOk = false;
            if (SlaveStateSize!.IsOnline)
            {
                SizeServer!.SendMsgAsync(MsgPackHelper.GetDataClearMsgSend("Size"));
            }
            if (SlaveStateSmudge!.IsOnline)
            {
                SmudgeServer!.SendMsgAsync(MsgPackHelper.GetDataClearMsgSend("Smudge"));
            }
            if (SlaveState3D!.IsOnline)
            {
                ThreeDServer!.SendMsgAsync(MsgPackHelper.GetDataClearMsgSend("3D"));
            }
            if (SlaveStateEdgeSub!.IsOnline)
            {
                EdgeSubServer!.SendMsgAsync(MsgPackHelper.GetDataClearMsgSend("EdgeSub"));
            }
        }

        #endregion


        #region 2. UI界面绑定的CLR对象
        private ObservableCollection<string>? _boxNumberList;

        public ObservableCollection<string>? BoxNumberList
        {
            get { return _boxNumberList; }
            set
            {
                _boxNumberList = value;
                RaisePropertyChanged();
            }
        }

        private int _boxNumberIndexSelected;

        public int BoxNumberIndexSelected
        {
            get { return _boxNumberIndexSelected; }
            set
            {
                _boxNumberIndexSelected = value;
                RaisePropertyChanged();
            }
        }



        /// <summary>
        /// 关于界面上尺寸的一些属性
        /// </summary>

        private int _radioButtonFont;

        public int RadioButtonFont
        {
            get { return _radioButtonFont; }
            set
            {
                _radioButtonFont = value;
                RaisePropertyChanged();
            }
        }

        private int _radionButtonTextFont;

        public int RadioButtonTextFont
        {
            get { return _radionButtonTextFont; }
            set
            {
                _radionButtonTextFont = value;
                RaisePropertyChanged();
            }
        }

        private int _boxWidth;

        public int BoxWidth
        {
            get { return _boxWidth; }
            set
            {
                _boxWidth = value;
                RaisePropertyChanged();
            }
        }

        private int _boxHeight;

        public int BoxHeight
        {
            get { return _boxHeight; }
            set
            {
                _boxHeight = value;
                RaisePropertyChanged();
            }
        }

        private int _fontBoxSmall;

        public int FontBoxSmall
        {
            get { return _fontBoxSmall; }
            set
            {
                _fontBoxSmall = value;
                RaisePropertyChanged();
            }
        }

        private int _fontBoxBig;

        public int FontBoxBig
        {
            get { return _fontBoxBig; }
            set
            {
                _fontBoxBig = value;
                RaisePropertyChanged();
            }
        }

        private int _lineWidth;

        public int LineWidth
        {
            get { return _lineWidth; }
            set
            {
                _lineWidth = value;
                RaisePropertyChanged();
            }
        }

        private int _lineHeight;

        public int LineHeight
        {
            get { return _lineHeight; }
            set
            {
                _lineHeight = value;
                RaisePropertyChanged();
            }
        }

        private int _boardWidth;

        public int BoardWidth
        {
            get { return _boardWidth; }
            set
            {
                _boardWidth = value;
                RaisePropertyChanged();
            }
        }

        private int _boardHeight;

        public int BoardHeight
        {
            get { return _boardHeight; }
            set
            {
                _boardHeight = value;
                RaisePropertyChanged();
            }
        }
        private int _boardRadiusVal;

        public int BoardRadiusVal
        {
            get { return _boardRadiusVal; }
            set
            {
                _boardRadiusVal = value;
                RaisePropertyChanged();
            }
        }


        private void SetUiElementSize(WindowSize size)
        {
            BoxHeight = Convert.ToInt32(0.027 * size.Height);
            BoxWidth = Convert.ToInt32(0.05 * size.Width);
            FontBoxSmall = Convert.ToInt32(size.Height * 0.012);
            FontBoxBig = Convert.ToInt32(size.Height * 0.015);
            LineWidth = Convert.ToInt32(3.35 * BoxWidth); // 线体宽度自适应,目前屏幕大的时候有点长
            LineHeight = Convert.ToInt32(0.005 * size.Height);
            BoardWidth = Convert.ToInt32(size.Width * 0.015);
            BoardHeight = Convert.ToInt32(size.Height * 0.05);
            BoardRadiusVal = Convert.ToInt32(BoardWidth / 2);
            RadioButtonFont = Convert.ToInt32(size.Width * 0.02);
            RadioButtonTextFont = Convert.ToInt32(RadioButtonFont * 0.8);
        }

        private string? _cvButtonName = "CV清洗";

        public string? CvButtonName
        {
            get { return _cvButtonName; }
            set
            {
                _cvButtonName = value;
                RaisePropertyChanged();
            }
        }


        private WorkingInfoEntity _workingInfo = null!;
        /// <summary>
        /// 当前的作业信息
        /// </summary>
        public WorkingInfoEntity WorkingInfo
        {
            get { return _workingInfo; }
            set
            {
                _workingInfo = value;
                // 每次WorkingInfo更新的时候去更新一次全局变量
                PathDirProvider.RecipeImportDir = value.RecipeImportDir!;
                PathDirProvider.RecipeImportFilename = value.RecipeImportFileName!;
                RaisePropertyChanged();
            }
        }


        private bool _currentCrystalIsChecked = true;
        /// <summary>
        /// 当晶棒信息是否被选中,默认是选中状态
        /// </summary>
        public bool CurrentCrystalIsChecked
        {
            get { return _currentCrystalIsChecked; }
            set
            {
                _currentCrystalIsChecked = value;
                RaisePropertyChanged();
            }
        }

        private ObservableCollection<CrystalLevelCountModel> _levelCountsList = new ObservableCollection<CrystalLevelCountModel>();
        /// <summary>
        /// 主界面左侧类型和个数统计表
        /// </summary>
        public ObservableCollection<CrystalLevelCountModel> LevelCountsList
        {
            get { return _levelCountsList; }
            set
            {
                _levelCountsList = value;
                RaisePropertyChanged();
            }
        }

        private ObservableCollection<string> _recipeNamesList = new ObservableCollection<string>();
        /// <summary>
        /// 工单名称列表
        /// </summary>
        public ObservableCollection<string> RecipeNamesList
        {
            get { return _recipeNamesList; }
            set
            {
                _recipeNamesList = value;
                RaisePropertyChanged();
            }
        }

        private int _recipeSelectedIndex;
        /// <summary>
        /// 选中的工单索引
        /// </summary>
        public int RecipeSelectedIndex
        {
            get { return _recipeSelectedIndex; }
            set
            {
                _recipeSelectedIndex = value;
                RaisePropertyChanged();
            }
        }

        // 下一单是否输入OK
        private bool _nextCrystalIsOk;

        public bool NextCrystalIsOk
        {
            get { return _nextCrystalIsOk; }
            set
            {
                _nextCrystalIsOk = value;
                RaisePropertyChanged();
            }
        }

        private ObservableCollection<SlaveStateModel> _slaveStates = new ObservableCollection<SlaveStateModel>();

        /// <summary>
        /// 从站状态,电阻率
        /// </summary>
        private SlaveStateModel? _slaveStateNapons;

        public SlaveStateModel? SlaveStateNapons
        {
            get { return _slaveStateNapons; }
            set
            {
                _slaveStateNapons = value;
                RaisePropertyChanged();
            }
        }

        /// <summary>
        /// 从站状态,尺寸
        /// </summary>
        private SlaveStateModel? _slaveStateSize;

        public SlaveStateModel? SlaveStateSize
        {
            get { return _slaveStateSize; }
            set
            {
                _slaveStateSize = value;
                RaisePropertyChanged();
            }
        }


        private SlaveStateModel? _slaveStateEdgeSub;
        /// <summary>
        /// 从站状态,崩边隐裂
        /// </summary>
        public SlaveStateModel? SlaveStateEdgeSub
        {
            get { return _slaveStateEdgeSub; }
            set
            {
                _slaveStateEdgeSub = value;
                RaisePropertyChanged();
            }
        }

        private SlaveStateModel? _slaveState3D;
        /// <summary>
        /// 从站状态,3D
        /// </summary>
        public SlaveStateModel? SlaveState3D
        {
            get { return _slaveState3D; }
            set
            {
                _slaveState3D = value;
                RaisePropertyChanged();
            }
        }

        private SlaveStateModel? _slaveStateSmudge;
        /// <summary>
        /// 从站状态,脏污
        /// </summary>
        public SlaveStateModel? SlaveStateSmudge
        {
            get { return _slaveStateSmudge; }
            set
            {
                _slaveStateSmudge = value;
                RaisePropertyChanged();
            }
        }
        private SlaveStateModel _slaveStatePlc = null!;
        /// <summary>
        /// 从站状态,Plc
        /// </summary>
        public SlaveStateModel SlaveStatePlc
        {
            get { return _slaveStatePlc; }
            set
            {
                _slaveStatePlc = value;
                RaisePropertyChanged();
            }
        }

        private ObservableCollection<string> _moduleShieldedList = new ObservableCollection<string>();
        /// <summary>
        /// 已屏幕模块
        /// </summary>
        public ObservableCollection<string> ModuleShieldedList
        {
            get { return _moduleShieldedList; }
            set
            {
                _moduleShieldedList = value;
                // 更新模块屏幕
                GlobalValues.ShieldModules = value.ToList();
                RaisePropertyChanged();
            }
        }

        private ObservableCollection<ModuleShieldedModel> _totalModuleShieldStates = new ObservableCollection<ModuleShieldedModel>();
        /// <summary>
        /// 所有的模块屏蔽状态
        /// </summary>
        public ObservableCollection<ModuleShieldedModel> TotalModuleShieldStates
        {
            get { return _totalModuleShieldStates; }
            set
            {
                _totalModuleShieldStates = value;
                RaisePropertyChanged();
            }
        }

        /// <summary>
        /// PLC运行状态,为True,表示正在运行
        /// </summary>
        private bool _plcRunningState;

        public bool PlcRunningState
        {
            get { return _plcRunningState; }
            set
            {
                if (_plcRunningState != value)
                {
                    _plcRunningState = value;
                    RaisePropertyChanged();
                    if (value)
                    {
                        RunStopRadioColor = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#00AC6A"));
                    }
                }
            }
        }


        private bool _plcStopState;

        public bool PlcStopState
        {
            get { return _plcStopState; }
            set
            {
                if (_plcStopState != value)
                {
                    _plcStopState = value;
                    RaisePropertyChanged();
                    if (value)
                    {
                        RunStopRadioColor = new SolidColorBrush(Colors.Red);
                    }
                }
            }
        }


        private SolidColorBrush? _runStopRadioColor;
        /// <summary>
        /// 运行停止按钮的背景色,运行为绿色,停止未红色
        /// </summary>
        public SolidColorBrush? RunStopRadioColor
        {
            get { return _runStopRadioColor; }
            set
            {
                _runStopRadioColor = value;
                RaisePropertyChanged();
            }
        }


        private ObservableCollection<BoxStateModel> _boxStateList = new ObservableCollection<BoxStateModel>();
        /// <summary>
        /// 界面上显示的料盒状态
        /// </summary>
        public ObservableCollection<BoxStateModel> BoxStateList
        {
            get { return _boxStateList; }
            set
            {
                _boxStateList = value;
                RaisePropertyChanged();
            }
        }

        #endregion

        #region 3. 数据刷新方法(从数据库中刷新)

        // 1. 从数据库中刷新WorkingInfo
        private void ReloadWorkingInfo()
        {
            DataResult<WorkingInfoEntity> result = WorkingInfoAccess.GetWorkingInfo();
            if (result.State)
            {
                var workingInfo = result.Data!;
                if (workingInfo != null)
                {
                    Application.Current?.Dispatcher.Invoke(() =>
                    {
                        // 加载成功之后,就更新当前的作业信息
                        WorkingInfo = workingInfo;
                    });
                }
                else
                {
                    // 如果workingInfo里面的数据为Null,一般是数据初始化的时候,这个时候就添加一条默认数据进去即可
                    WorkingInfoEntity newWorkingInfo = new WorkingInfoEntity()
                    {
                        FlowerNumber = "001",
                        ProductionDate = DateTimeHelper.GetProductionDateTime(),
                        CutNumber = "Test001",
                        CurrentCrystalNumber = "Test001",
                        LastCrystalNumber = "Test001",
                        TheoryCounts = 4000,
                        RealCounts = 0,
                        TotalCountInFromPlc = 0,
                        TotalCountOutFromPlc = 0,
                        TotalCountFromPc = 0,
                        PositionNumber = "1",
                        ProductionLot = "Lot01",
                        ProductionRecipe = PathDirProvider.RecipeImportFilename,
                        RecipeImportDir = PathDirProvider.RecipeImportDir,
                        RecipeImportFileName = PathDirProvider.RecipeImportFilename,
                        ResultSummaryExportDir = PathDirProvider.SummaryExportDir
                    };
                    var addResult = WorkingInfoAccess.AddWorkingInfo(newWorkingInfo);
                    if (!addResult.State)
                    {
                        LoggerHelper.WriteLogMain(addResult.Message!, LogType.Exception);
                    }

                    Application.Current?.Dispatcher.Invoke(() =>
                    {
                        WorkingInfo = newWorkingInfo;
                    });
                }
                // 更新一下WaferSummary表,如果表不存在要创建这个表
                GlobalValues.CurrentCrystalName = WorkingInfo.CurrentCrystalNumber!;
            }
            else
            {
                LoggerHelper.WriteLogMain(result.Message!, LogType.Fatal);
            }
        }

        // 2. 从数据库中刷新CrystalLevelCout表数据
        private void ReloadCystalLevelCount()
        {
            var result = CrystalLevelCountAccess.GetLevelCountsByCrystalNumber(WorkingInfo.CurrentCrystalNumber!);
            if (result.State)
            {
                var levelCountRes = result.Data;
                // 先清空之前数据
                GlobalValues.DetectedTypeNamesTotal.Clear();
                Application.Current?.Dispatcher.Invoke(() =>
                {
                    LevelCountsList.Clear();
                    if (levelCountRes!.Count > 0)
                    {
                        foreach (var lvCountEntity in levelCountRes)
                        {
                            var temp = new CrystalLevelCountModel()
                            {
                                LevelIndex = lvCountEntity.LevelIndex,
                                DetectedType = lvCountEntity.LevelType,
                                DetectedCount = lvCountEntity.Count,
                            };
                            GlobalValues.DetectedTypeNamesTotal[lvCountEntity.LevelIndex] = lvCountEntity.LevelType!;
                            LevelCountsList.Add(temp);
                        }
                    }
                    else
                    {
                        // 检测当前作业工单是否存在,如果不存在要报错的.
                        DataResult<string> recipePathIsOk = CheckProductionRecipeIsOK();
                        if (!recipePathIsOk.State)
                        {
                            AppCloseProvider.CloseAppWithErrorHappen(result.Message!);
                        }
                        // 工单检测没有问题,加载对应工单上的信息
                        var recipeLevelBoxResult = ExcelHelper.GetRecipeLevelBoxInfo(recipePathIsOk.Data!);
                        if (!recipeLevelBoxResult.State)
                        {
                            AppCloseProvider.CloseAppWithErrorHappen(recipeLevelBoxResult.Message!);
                        }

                        // 将工单中的检测类型添加到首页上要显示的检测数量上去,这里要注意的点就是要添加上自定义的数据
                        foreach (var levelBoxData in recipeLevelBoxResult.Data!)
                        {
                            if (levelBoxData.IsUsed)
                            {
                                var temp = new CrystalLevelCountModel()
                                {
                                    LevelIndex = levelBoxData.Level,
                                    DetectedType = $"{levelBoxData.Level}.{levelBoxData.TypeDescription}",
                                    DetectedCount = 0,
                                };
                                LevelCountsList.Add(temp);
                                // 添加到全局的检测类型
                                GlobalValues.DetectedTypeNamesTotal[levelBoxData.Level] = levelBoxData.TypeDescription!;
                            }
                        }

                        // 将那些固定的检测的类型也加上
                        foreach (var item in GlobalValues.DetectedTypeNamesDefineSelf)
                        {
                            var temp = new CrystalLevelCountModel()
                            {
                                LevelIndex = item.Key,
                                DetectedType = item.Value,
                                DetectedCount = 0,
                            };
                            LevelCountsList.Add(temp);
                            // 添加到全局变量中去
                            GlobalValues.DetectedTypeNamesTotal[item.Key] = item.Value;
                        }

                        // 这个时候数据库中还不存在这些数据,所以要先将原始数据插入到数据库中去.先转换为其对应的实体类然后进行保存
                        List<CrystalLevelCountEntity> levelCountEntites = new List<CrystalLevelCountEntity>();
                        foreach (var item in LevelCountsList)
                        {
                            var levelCount = new CrystalLevelCountEntity()
                            {
                                CrystalNumber = WorkingInfo.CurrentCrystalNumber,
                                LevelIndex = item.LevelIndex,
                                LevelType = item.DetectedType,
                                Count = item.DetectedCount,
                            };
                            levelCountEntites.Add(levelCount);
                        }

                        DataResult insertRes = CrystalLevelCountAccess.AddCrystalLevelCountMany(levelCountEntites);
                        if (!insertRes.State)
                        {
                            AppCloseProvider.CloseAppWithErrorHappen(insertRes.Message!);
                        }
                    }
                });
            }
            else
            {
                LoggerHelper.WriteLogMain(result.Message!, LogType.Exception);
            }
        }

        // 3. 从作业工单目录中加载当前作业工单文件名
        private void ReloadProductionRecipeFiles()
        {
            try
            {
                Application.Current?.Dispatcher.Invoke(() =>
                {
                    RecipeNamesList.Clear();
                });
                DirectoryInfo root = new DirectoryInfo(PathDirProvider.ProductionRecipeDir);
                FileInfo[] fileArray = root.GetFiles();
                // 将其按照创建时间进行排序,是降序排列,因为y的创建时间比x大的时候才返回正
                Array.Sort(fileArray, (FileInfo x, FileInfo y) => y.CreationTime.CompareTo(x.CreationTime));
                Application.Current?.Dispatcher.Invoke(() =>
                {
                    foreach (FileInfo file in fileArray)
                    {
                        string name = file.Name;
                        string[] nameFilter = { ".xlsx", "csv" };
                        if (!string.IsNullOrEmpty(name) && nameFilter.Any(filter => name.EndsWith(filter)))
                        {
                            RecipeNamesList.Add(name);
                        }
                    }
                });

                if (RecipeNamesList.Count == 0)
                {
                    AppCloseProvider.CloseAppWithErrorHappen("生产工单目录为空,请先导入一个工单到生产目录");
                }

                // 看看当前WorkingInfo中的工单信息是否在这个目录中,如果不在的话,要默认选中一个工单.默认工单就是创建最晚的工单
                Application.Current?.Dispatcher?.Invoke(() =>
                {
                    if (!RecipeNamesList.Contains(WorkingInfo.ProductionRecipe!))
                    {
                        WorkingInfo.ProductionRecipe = RecipeNamesList[0];
                        RecipeSelectedIndex = 0;
                        // 更新到数据库
                        DataResult result = WorkingInfoAccess.UpdateWorkingInfo(WorkingInfo);
                        if (!result.State)
                        {
                            LoggerHelper.WriteLogMain(result.Message!, LogType.Fatal);
                        }
                    }
                    else
                    {
                        RecipeSelectedIndex = RecipeNamesList.IndexOf(WorkingInfo.ProductionRecipe!);
                    }
                });
            }
            catch (Exception ex)
            {
                LoggerHelper.WriteLogMain(ex.GetFullException(), LogType.Fatal);
            }
        }

        // 4. 从数据库中加载从站参数配置
        private void ReloadSlaveParams()
        {
            DataResult<List<SlaveParamsEntity>> result = SlaveParamsAccess.GetSlaveParams();
            if (result.State)
            {
                var slaveParams = result.Data;
                if (slaveParams!.Count > 0)
                {
                    // 更新SlaveState状态的值
                    Application.Current?.Dispatcher.Invoke(() =>
                    {
                        SlaveStateNapons = new SlaveStateModel()
                        {
                            SlaveName = slaveParams[0].SlaveName,
                            SlavePort = slaveParams[0].SlavePort,
                            SlaveIp = slaveParams[0].SlaveIp,
                            IsOnline = false,
                            DisConnectedCount = 0,
                        };
                        SlaveStateSize = new SlaveStateModel()
                        {
                            SlaveName = slaveParams[1].SlaveName,
                            SlavePort = slaveParams[1].SlavePort,
                            SlaveIp = slaveParams[1].SlaveIp,
                            IsOnline = false,
                            DisConnectedCount = 0,
                        };
                        SlaveStateEdgeSub = new SlaveStateModel()
                        {
                            SlaveName = slaveParams[2].SlaveName,
                            SlavePort = slaveParams[2].SlavePort,
                            SlaveIp = slaveParams[2].SlaveIp,
                            IsOnline = false,
                            DisConnectedCount = 0,
                        };
                        SlaveState3D = new SlaveStateModel()
                        {
                            SlaveName = slaveParams[3].SlaveName,
                            SlavePort = slaveParams[3].SlavePort,
                            SlaveIp = slaveParams[3].SlaveIp,
                            IsOnline = false,
                            DisConnectedCount = 0,
                        };
                        SlaveStateSmudge = new SlaveStateModel()
                        {
                            SlaveName = slaveParams[4].SlaveName,
                            SlavePort = slaveParams[4].SlavePort,
                            SlaveIp = slaveParams[4].SlaveIp,
                            IsOnline = false,
                            DisConnectedCount = 0,
                        };
                        SlaveStatePlc = new SlaveStateModel()
                        {
                            SlaveName = slaveParams[5].SlaveName,
                            SlavePort = slaveParams[5].SlavePort,
                            SlaveIp = slaveParams[5].SlaveIp,
                            IsOnline = false,
                            DisConnectedCount = 0,
                        };
                    });
                }
                else
                {
                    // 添加新的值
                    List<SlaveParamsEntity> slaveInitVals = new List<SlaveParamsEntity>()
                    {
                        new SlaveParamsEntity(){SlaveName = "1. 电阻率",SlaveIp = "192.168.1.10",SlavePort=10001},
                        new SlaveParamsEntity(){SlaveName="2. 尺寸",SlaveIp="192.168.0.102",SlavePort=5001},
                        new SlaveParamsEntity(){SlaveName="3. 崩边隐裂",SlaveIp="192.168.0.103",SlavePort=5002},
                        new SlaveParamsEntity(){SlaveName="4. 3D",SlaveIp="192.168.0.104",SlavePort=5003},
                        new SlaveParamsEntity(){SlaveName="5. 脏污",SlaveIp="192.168.0.105",SlavePort=5004},
                        new SlaveParamsEntity(){SlaveName="6. PLC",SlaveIp="5.125.213.151.1.1",SlavePort=851}
                    };
                    DataResult resultAdd = SlaveParamsAccess.AddSlaveParamMany(slaveInitVals);
                    if (resultAdd.State)
                    {
                        // 初始化更新状态
                        Application.Current?.Dispatcher.Invoke(() =>
                        {
                            SlaveStateNapons = new SlaveStateModel()
                            {
                                SlaveName = slaveInitVals[0].SlaveName,
                                SlavePort = slaveInitVals[0].SlavePort,
                                SlaveIp = slaveInitVals[0].SlaveIp,
                                IsOnline = false,
                                DisConnectedCount = 0,
                            };
                            SlaveStateSize = new SlaveStateModel()
                            {
                                SlaveName = slaveInitVals[1].SlaveName,
                                SlavePort = slaveInitVals[1].SlavePort,
                                SlaveIp = slaveInitVals[1].SlaveIp,
                                IsOnline = false,
                                DisConnectedCount = 0,
                            };
                            SlaveStateEdgeSub = new SlaveStateModel()
                            {
                                SlaveName = slaveInitVals[2].SlaveName,
                                SlavePort = slaveInitVals[2].SlavePort,
                                SlaveIp = slaveInitVals[2].SlaveIp,
                                IsOnline = false,
                                DisConnectedCount = 0,
                            };
                            SlaveState3D = new SlaveStateModel()
                            {
                                SlaveName = slaveInitVals[3].SlaveName,
                                SlavePort = slaveInitVals[3].SlavePort,
                                SlaveIp = slaveInitVals[3].SlaveIp,
                                IsOnline = false,
                                DisConnectedCount = 0,
                            };
                            SlaveStateSmudge = new SlaveStateModel()
                            {
                                SlaveName = slaveInitVals[4].SlaveName,
                                SlavePort = slaveInitVals[4].SlavePort,
                                SlaveIp = slaveInitVals[4].SlaveIp,
                                IsOnline = false,
                                DisConnectedCount = 0,
                            };
                            SlaveStatePlc = new SlaveStateModel()
                            {
                                SlaveName = slaveInitVals[5].SlaveName,
                                SlavePort = slaveInitVals[5].SlavePort,
                                SlaveIp = slaveInitVals[5].SlaveIp,
                                IsOnline = false,
                                DisConnectedCount = 0,
                            };
                        });
                    }
                    else
                    {
                        LoggerHelper.WriteLogMain(resultAdd.Message!, LogType.Fatal);
                    }
                }
            }
            else
            {
                LoggerHelper.WriteLogMain(result.Message!, LogType.Fatal);
            }

        }

        // 5. 加载当前工单的检测规则
        private void ReloadDetectedRules()
        {
            try
            {
                string productionRecipePath = Path.Combine(PathDirProvider.ProductionRecipeDir, PathDirProvider.ProductionRecipeName);
                if (!File.Exists(productionRecipePath))
                {
                    AppCloseProvider.CloseAppWithErrorHappen($"工单路径文件不存在: {productionRecipePath}");
                }
                DataResult<List<List<string>>> ruleContentResult = DetectedRuleHelper.GetRecipeDetectedRuleContent(productionRecipePath);
                if (!ruleContentResult.State)
                {
                    AppCloseProvider.CloseAppWithErrorHappen(ruleContentResult.Message!);
                }

                // 1. 文件加载成功之后,先去清空检测规则文件里面的内容
                FileOperateHelper.CreateAnEmptyFile(PathDirProvider.DetectedRulePath);
                var ruleContentData = ruleContentResult.Data;
                foreach (var ruleContent in ruleContentData!)
                {
                    int dataLen = ruleContent.Count;
                    // 因为表格后面可能有空数据,空数据加载的时候可能在List中并没有数据,默认的Model中检测的等级是23个
                    var ruleModel = new RecipeDectectedRuleModel()
                    {
                        DetectedName = 0 < dataLen ? ruleContent[0].Trim('\"') : "",
                        Description = 1 < dataLen ? ruleContent[1].Trim('\"') : "",
                        Unit = 2 < dataLen ? ruleContent[2].Trim('\"') : "",
                        Precis = 3 < dataLen ? ruleContent[3].Trim('\"') : "",
                        Level01Val = 4 < dataLen ? ruleContent[4].Trim('\"') : "",
                        Level02Val = 5 < dataLen ? ruleContent[5].Trim('\"') : "",
                        Level03Val = 6 < dataLen ? ruleContent[6].Trim('\"') : "",
                        Level04Val = 7 < dataLen ? ruleContent[7].Trim('\"') : "",
                        Level05Val = 8 < dataLen ? ruleContent[8].Trim('\"') : "",
                        Level06Val = 9 < dataLen ? ruleContent[9].Trim('\"') : "",
                        Level07Val = 10 < dataLen ? ruleContent[10].Trim('\"') : "",
                        Level08Val = 11 < dataLen ? ruleContent[11].Trim('\"') : "",
                        Level09Val = 12 < dataLen ? ruleContent[12].Trim('\"') : "",
                        Level10Val = 13 < dataLen ? ruleContent[13].Trim('\"') : "",
                        Level11Val = 14 < dataLen ? ruleContent[14].Trim('\"') : "",
                        Level12Val = 15 < dataLen ? ruleContent[15].Trim('\"') : "",
                        Level13Val = 16 < dataLen ? ruleContent[16].Trim('\"') : "",
                        Level14Val = 17 < dataLen ? ruleContent[17].Trim('\"') : "",
                        Level15Val = 18 < dataLen ? ruleContent[18].Trim('\"') : "",
                        Level16Val = 19 < dataLen ? ruleContent[19].Trim('\"') : "",
                        Level17Val = 20 < dataLen ? ruleContent[20].Trim('\"') : "",
                        Level18Val = 21 < dataLen ? ruleContent[21].Trim('\"') : "",
                        Level19Val = 22 < dataLen ? ruleContent[22].Trim('\"') : "",
                        Level20Val = 23 < dataLen ? ruleContent[23].Trim('\"') : "",
                        Level21Val = 24 < dataLen ? ruleContent[24].Trim('\"') : "",
                    };
                    DataResult loadResult = DetectedRuleHelper.LoadRuleToDictionary(ruleModel);
                    if (!loadResult.State)
                    {
                        AppCloseProvider.CloseAppWithErrorHappen(loadResult.Message!);
                    }
                }
            }
            catch (Exception ex)
            {
                AppCloseProvider.CloseAppWithErrorHappen(ex.GetFullException());
            }
        }

        // 6. 加载视觉补偿表
        private void ReloadVisionOffsets()
        {
            var result = VisionOffsetAccess.GetVisionOffsets();
            if (!result.State)
            {
                AppCloseProvider.CloseAppWithErrorHappen(result.Message!);
            }
            var visionOffsetList = result.Data!;
            if (visionOffsetList.Count == 0)
            {
                // 初始化visonOffset数据
                List<VisionOffsetEntity> initDataList = new List<VisionOffsetEntity>
                {
                    new VisionOffsetEntity() { ModuleName = "3D线激光测量", OptionName = "平均厚度", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "3D线激光测量", OptionName = "TTV", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "3D线激光测量", OptionName = "线痕最大值", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "3D线激光测量", OptionName = "翘曲", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "3D线激光测量", OptionName = "最小厚度", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "3D线激光测量", OptionName = "最大厚度", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "3D线激光测量", OptionName = "是否密集线痕", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "3D线激光测量", OptionName = "上线痕数量", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "3D线激光测量", OptionName = "上线痕数量最大值", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "3D线激光测量", OptionName = "下线痕数量", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "3D线激光测量", OptionName = "下线痕数量最大值", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "3D线激光测量", OptionName = "线痕数量", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "边长最大值", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "边长最小值", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "X边长", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "Y边长", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "对角线左上右下", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "对角线右上左下", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "倒角最大值", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "倒角最小值", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "上下平行度", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "左右平行度", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "直角边最大值", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "直角边最小值", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "垂直度最大值", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "垂直度最小值", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "左上倒角", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "右上倒角", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "左下倒角", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "右下倒角", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "左上角度", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "右上角度", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "左下角度", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "右下角度", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "X边长最大值", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "X边长最小值", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "Y边长最大值", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "尺寸", OptionName = "Y边长最小值", OffsetK = 1.0, OffsetB = 0.0 },
                    new VisionOffsetEntity() { ModuleName = "电阻率", OptionName = "电阻率值", OffsetK = 1.0, OffsetB = 0.0 },
                };

                DataResult insertDataResult = VisionOffsetAccess.AddDataMany(initDataList);
                if (insertDataResult.State)
                {
                    // 插入成功,将数据写入到全局的VisionOffsetMap中去
                    VisionOffsetViewModel.UpdateVisionOffsetGlobalMap(initDataList);
                }
                else
                {
                    AppCloseProvider.CloseAppWithErrorHappen(insertDataResult.Message!);
                }
            }
            else
            {
                // 数据已经存在就直接去加载即可
                VisionOffsetViewModel.UpdateVisionOffsetGlobalMap(visionOffsetList);
            }
        }

        // 7. 加载模块屏蔽配置
        private void ReloadShieldModules()
        {
            var result = ModuleShieldAccess.GetTotalShieldModules();
            Application.Current?.Dispatcher?.Invoke(() =>
            {
                if (result.State)
                {
                    if (result.Data!.Count == 0)
                    {
                        // 如果数据为空,插入默认数据
                        List<ModuleShieldEntity> initData = new List<ModuleShieldEntity>();
                        ModuleShieldedList.Clear();
                        TotalModuleShieldStates.Clear();
                        foreach (var moduleName in ConstantProvider.MsgHeaderClientMap.Values)
                        {
                            TotalModuleShieldStates.Add(new ModuleShieldedModel() { ModuleName = moduleName, IsShielded = false });
                            initData.Add(new ModuleShieldEntity() { ModuleName = moduleName, IsShielded = false });
                        }
                        var dataInitResult = ModuleShieldAccess.AddDataMany(initData);
                        if (!dataInitResult.State)
                        {
                            LoggerHelper.WriteLogMain(dataInitResult.Message!, LogType.Fatal);
                        }
                    }
                    else
                    {
                        Application.Current?.Dispatcher.Invoke(() =>
                        {
                            ModuleShieldedList.Clear();
                            TotalModuleShieldStates.Clear();
                            foreach (var item in result.Data!)
                            {
                                TotalModuleShieldStates.Add(new ModuleShieldedModel() { Id = item.Id, ModuleName = item.ModuleName, IsShielded = item.IsShielded });
                                if (item.IsShielded)
                                    ModuleShieldedList.Add(item.ModuleName!);
                            }
                        });
                    }
                }
                else
                {
                    AppCloseProvider.CloseAppWithErrorHappen(result.Message!);
                }
            });
        }

        // 8. 加载料盒状态信息
        private void ReloadBoxStates()
        {
            var result = BoxStateAccess.GetBoxStates();
            Application.Current?.Dispatcher.Invoke(() =>
            {
                if (result.State)
                {
                    if (result.Data!.Count == 0)
                    {
                        DataResult initRes = BoxStateAccess.DataInit();
                        if (!initRes.State)
                        {
                            AppCloseProvider.CloseAppWithErrorHappen(result.Message!);
                        }
                        result = BoxStateAccess.GetBoxStates();
                        if (!result.State)
                        {
                            AppCloseProvider.CloseAppWithErrorHappen(result.Message!);
                        }
                    }
                    // 1. 先清空模型中数据,然后加载料盒数据库设定的内容
                    BoxStateList.Clear();
                    foreach (var box in result.Data!)
                    {
                        var model = new BoxStateModel()
                        {
                            Id = box.Id,
                            BoxNumber = box.BoxNumber,
                            UpCountPc = box.UpCount,
                            DownCountPc = box.DownCount,
                            CountMax = box.CountMax,
                            LockedSeconds = box.BoxLockedSeconds,
                            UpCountPlc = 0,
                            DownCountPlc = 0
                        };
                        BoxStateList.Add(model);
                    }

                    // 2. 然后就是加载工单中的配置,工单中主要是加载料盒显示的等级以及类型
                    DataResult<string> recipePathIsOk = CheckProductionRecipeIsOK();
                    if (!recipePathIsOk.State)
                    {
                        AppCloseProvider.CloseAppWithErrorHappen(result.Message!);
                    }
                    // 工单检测没有问题,加载对应工单上的信息
                    var recipeLevelBoxResult = ExcelHelper.GetRecipeLevelBoxInfo(recipePathIsOk.Data!);
                    if (!recipeLevelBoxResult.State)
                    {
                        AppCloseProvider.CloseAppWithErrorHappen(recipeLevelBoxResult.Message!);
                    }

                    // 将工单中的检测类型添加到首页上要显示的检测数量上去,这里要注意的点就是要添加上自定义的数据
                    foreach (var levelBoxData in recipeLevelBoxResult.Data!)
                    {
                        // 将料盒以及料盒对应的等级写到列表中去,料盒序号是从1到18,然后等级是从1开始的.
                        if (!string.IsNullOrEmpty(levelBoxData.BoxesInto))
                        {
                            // 先给料盒分解成List<int>
                            var boxesInto = levelBoxData.BoxesInto!.Split(',').Select(int.Parse).ToList();
                            // 保存到全局的料盒信息中,然后分选的时候就按照这个去分
                            GlobalValues.LevelBoxMap[levelBoxData.Level] = boxesInto;
                            // 将料盒保存到类型进行赋值,主要是界面显示料盒对应的等级类型

                            foreach (var boxNumber in boxesInto)
                            {
                                if (boxNumber > 18)
                                {
                                    MessageBox.Show("料盒信息错误,请重新编辑工单料盒信息,设置的料盒大于18");
                                }
                                else
                                {
                                    if (string.IsNullOrWhiteSpace(BoxStateList[boxNumber - 1].LevelType))
                                    {
                                        BoxStateList[boxNumber - 1].LevelType = levelBoxData.TypeDescription;
                                    }
                                    else
                                    {
                                        BoxStateList[boxNumber - 1].LevelType = BoxStateList[boxNumber - 1].LevelType + " " + levelBoxData.TypeDescription;
                                    }
                                }
                            }
                        }
                    }
                }
                else
                {
                    AppCloseProvider.CloseAppWithErrorHappen(result.Message!);
                }
            });
        }

        // 10. 加载料盒名称
        private void ReloadBoxNameList()
        {
            BoxNumberList = new ObservableCollection<string>()
            {
                "料盒1","料盒2","料盒3","料盒4","料盒5","料盒6","料盒7","料盒8","料盒9",
                "料盒10","料盒11","料盒12","料盒13","料盒14","料盒15","料盒16","料盒17","料盒18"
            };

        }

        /// <summary>
        /// 检测当前作业工单是否存在
        /// </summary>
        /// <returns></returns>
        private DataResult<string> CheckProductionRecipeIsOK()
        {
            DataResult<string> result = new DataResult<string>();
            try
            {
                string productionRecipePath = Path.Combine(PathDirProvider.ProductionRecipeDir, PathDirProvider.ProductionRecipeName);
                if (File.Exists(productionRecipePath))
                {
                    result.Data = productionRecipePath;
                    result.State = true;
                }
                else
                {
                    result.Message = $"生产配路径文件不存在,请先导入工单再生产,路径地址:{productionRecipePath}";
                }
            }
            catch (Exception ex)
            {
                result.Message = ex.GetFullException();
            }
            return result;
        }

        #endregion

        #region 一些异步任务

        #endregion

    }
}
